threst's Blog

逆向入门--ARM64的linux

2018/05/12 Share

序幕

正如您知道的那样,ARM为我们周围的各种低功耗设备供电,包括但不限于电话,路由器,物联网设备等。因此,深入研究这种体系结构并理解它与x86和x64体系结构有何不同之处是合理的。对于这篇文章,我们将重点介绍目前最常用的64位ARM CPU。我们的设备包括ARM Cortex-A53 CPU的Ubuntu 16.04,它支持32位和64位指令集。

在之前的文章中,我们逆向了x64Linux和Windows中的C++二进制文件。在这篇文章中,我们将会使用同样的程序,但用c语言重写。

编译程序:

$ gcc crack_me.c -o crack_me

####二进制信息:

反编译

现在让我们用启动GDB二进制并开始分析。请注意,我使用GEF(https://github.com/hugsy/gef)和GDB,所以我的提示符看起来像gef>而不是gdb>。我们先分解一下主要功能。

$ gdb ./crack_me

gef> disas main

我们的注意力直接转向<main + 64>处的<check_pass>函数,但在之前,您可能需要花点时间并理解这些指令的含义。您可以在ARM的文档(https://developer.arm.com/docs/100069/latest/a64-general-instructions)上阅读更多关于这些内容的信息。
以下是对我们的分析很重要的一些说明。

b -分支到标签,类似于jmp语句
bl -分支到链接到标签,类似于调用语句
b.ne -分支到标签,如果不相等,类似于jne语句
b.eq -分支到标签,如果相等,类似于je声明

让我们深入汇编代码。编号是指在gdb反汇编输出中突出显示的部分。

1.在地址0x4007bc<main+4>,堆栈指针(SP)寄存器是MOV “ED寄存器X29。然后我们注意到从x29寄存器访问的主要函数参数。请注意,x29寄存器的偏移量28包含argc,而偏移量16包含argv(这是我们的输入密码)。在比较argc值时,如果它等于0x2,我们将(b.eq – branch if equal)分支到<main + 52>
2.接下来的三行<main + 52><main + 56><main + 60>argv字符串的大小从16扩展到24(16 + 0x8 = 24),并由x0寄存器引用。
3.然后我们调用(bl – branch with link)<check_pass>函数。

我们来拆开<check_pass>函数。

gef> disas check_pass

4.在地址 0x400738,<check_pass+8>,新的argv字符串从x0寄存器复制到x29寄存器。偏移量为24。然后,我们看到一些堆栈的canary操作,从<check_pass+12><check_pass+24>,有一些被储存在x29寄存器中,地址是0x411048,然后在函数的末尾,从<check_pass + 96>开始,直到<check_pass + 124>
5.回到<check_pass>函数的主体,我们看到从<check_pass + 32>开始,有些东西被访问从0x4008d0,并被储存到x29寄存器中,有偏移0x28(40),可能是秘密密码?
6.然后从<check_pass + 60>开始,x1寄存器指向从0x4008d0x0寄存器中新复制的数据到x29寄存器中的argv字符串,偏移量为24,然后调用strcmp (x0 & x1)函数。strcmp函数的返回值存储在16位通用w0寄存器中。如果字符串相等,则w0设置为0x0,否则设置为0x1

回到<main>功能…

7.<check_pass>函数的返回值存储在w0寄存器中,该值被复制到偏移量为44的x29寄存器中。然后在<main + 76>处比较w0寄存器的值以查看它是否等于0x1。如果不是,我们跳转(b.ne – branch if not equal)<main + 100>,这将导致我们获得成功消息,最后退出程序。
现在我们将用错误的密码启动该程序。但在此之前,我们必须在<main + 76>的比较语句中添加断点。

gef> break *0x400804

gef> run pass123

我们在0x400804<main+76>的比较语句中击中了断点另外,请注意x0寄存器的值是0x1。因为,x0指针只是w0寄存器+ 32位额外位,x0包含<check_pass>函数的返回值。从源代码中,我们知道程序将检查check_pass函数的返回值是否为1,以显示“错误密码”消息。因此,该值应该是除了0x1之外的任何值,以便程序向我们显示成功消息。

让我们改变它的价值…

gef> set $x0=0x0

现在让我们继续执行。

gef> continue

结语

原来我们的假设是正确的。将x0的值从0x1更改为0x0的技巧。这意味着它会一直检查w0是否设置为0x1来显示不正确的消息,我们从程序的源代码中知道这一点。因此,回到<check_pass>函数,我们注意到从地址0x4008d0复制了一些东西。我们来检查一下。

这看起来不像任何有效的汇编指令,但53的重复是可疑的,41也是十六进制的'A‘。这绝对看起来像一个常量字符串。让我们看看更深。从我们的地址0x4008d0转储10多行…

查看0x4008d00x4008d4,我们可以看出它是little-endian 8位字符串。让我们尝试解码它…

这里我们有原始密码“ PASSWORD ”

这只是使用gdb分析二进制文件在不同的体系结构中的一个例子。展望未来,我们将处理更复杂的程序,不常见的架构和更奇怪的二进制文件。
原文地址:https://scriptdotsh.com/index.php/2018/04/26/ground-zero-part-3-reverse-engineering-basics-linux-on-arm64/

CATALOG
  1. 1. 序幕
    1. 1.0.1. 编译程序:
  • 2. 反编译
  • 3. 结语